package com.hlf.robot.utils;

import okhttp3.*;
import org.springframework.core.io.ClassPathResource;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author 郝龙飞
 * @date 2023/9/11 15:30
 */
public class OkHttpUtil {
    public static final MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8");
    public static final MediaType FORM_DATA = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
    public static Integer connectionTimeout = 3;
    public static Integer readTimeout = 3;

    private static final Map<String, String> emptyMap = new HashMap<>();

    public static OkHttpClient okHttpClient = new OkHttpClient.Builder().readTimeout(readTimeout, TimeUnit.SECONDS)
            .connectTimeout(connectionTimeout, TimeUnit.SECONDS)
            .build();

    public static OkHttpResponse doPost(String url, String context, MediaType mediaType) throws IOException {
        return doPost(url, context, emptyMap, mediaType);
    }

    public static OkHttpResponse doPost(String url, String context) throws IOException {
        return doPost(url, context, emptyMap, JSON_TYPE);
    }


    public static OkHttpResponse doPost(String url, String context, Map<String, String> header) throws IOException {
        return doPost(url, context, header, JSON_TYPE);
    }

    public static OkHttpResponse doPost(String url, String context, Map<String, String> header, MediaType mediaType) throws IOException {
        Request.Builder request = new Request.Builder().post(RequestBody.create(mediaType, context))
                .url(url);
        for (Map.Entry<String, String> entry : header.entrySet()) {
            request.addHeader(entry.getKey(), entry.getValue());
        }
        return doCall(request.build());
    }

    public static OkHttpResponse doPostForm(String url, Map<String, Object> data) throws IOException {
        return doPostForm(url, data, emptyMap);
    }

    public static OkHttpResponse doPostForm(String url, Map<String, Object> data, Map<String, String> header) throws IOException {
        FormBody.Builder builder = new FormBody.Builder();
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            builder.addEncoded(entry.getKey(), Strings.urlEncode(String.valueOf(entry.getValue())));
        }
        Request.Builder builder2 = new Request.Builder().post(builder.build());
        for (Map.Entry<String, String> entry : header.entrySet()) {
            builder2.addHeader(entry.getKey(), entry.getValue());
        }
        return doCall(builder2.url(url).build());
    }

    public static OkHttpResponse doGet(String url) throws IOException {
        return doGet(url, emptyMap);
    }

    public static OkHttpResponse doGet(String url, Map<?, ?> context) throws IOException {
        return doGet(url, context, emptyMap);
    }

    public static OkHttpResponse doGet(String url, Map<?, ?> context, Map<String, String> header) throws IOException {
        String newUrl = Strings.url(url, context);
        Request request = new Request.Builder().get()
                .url(newUrl)
                .headers(Headers.of(header))
                .build();
        return doCall(request);
    }

    public static void asyncPostJson(String url, String context, Callback callback) {
        asyncPost(url, context, JSON_TYPE, callback);
    }

    public static void asyncPostForm(String url, Map<?, ?> context, Callback callback) {
        asyncPost(Strings.url(url, context), "", FORM_DATA, callback);
    }


    public static void asyncPost(String url, String context, MediaType mediaType, Callback callback) {
        Request request = new Request.Builder().post(RequestBody.create(mediaType, context))
                .url(url)
                .build();
        asyncCall(request, callback);
    }

    public static void asyncGet(String url, Callback callback) {
        asyncGet(url, emptyMap, callback);
    }

    public static void asyncGet(String url, Map<?, ?> context, Callback callback) {
        String newUrl = Strings.url(url, context);
        Request request = new Request.Builder().get()
                .url(newUrl)
                .build();
        asyncCall(request, callback);
    }


    public static OkHttpResponse doCall(Request request) throws IOException {
        try {

            Call call = okHttpClient.newCall(request);
            Response response = call.execute();
            OkHttpResponse responseEntity = OkHttpResponse.read(response);
            response.close();
            return responseEntity;
        } catch (Exception e) {
            throw new IOException(String.format("OKHttp request error [SubException:%s,message:%s,url:%s]", e.getClass().getName(), e.getMessage(), request.url().url().toString()));
        }
    }


    public static void asyncCall(Request request, Callback callback) {
        Call call = okHttpClient.newCall(request);
        call.enqueue(callback);
    }


    public static OkHttpResponse doCallSSL(Request request, SSLContext sslContext, TlsVersion tlsVersion) throws IOException {
        try {
            ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                    .tlsVersions(tlsVersion)
                    .cipherSuites(
                            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                            CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
                            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
                            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
                            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
                            CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
                            CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
                            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
                    .build();

            OkHttpClient okHttpClient = new OkHttpClient().newBuilder().readTimeout(readTimeout, TimeUnit.SECONDS)
                    .connectTimeout(connectionTimeout, TimeUnit.SECONDS)
                    .connectionSpecs(Collections.singletonList(spec))
                    .sslSocketFactory(sslContext.getSocketFactory())
                    .build();

            Call call = okHttpClient.newCall(request);
            Response response = call.execute();
            OkHttpResponse responseEntity = OkHttpResponse.read(response);
            response.close();
            return responseEntity;
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException(String.format("OKHttp request error [SubException:%s,message:%s,url:%s]", e.getClass().getName(), e.getMessage(), request.url().url().toString()));
        }
    }

    public static SSLContext getSSLContext(String certPath, String certPass, String tlsVersion) throws RuntimeException {

        try {
            char[] passArray = certPass.toCharArray();
            KeyStore clientStore = KeyStore.getInstance("PKCS12");
            // 读取resource下的文件 支持jar方式启动
            InputStream inputStream = new ClassPathResource(certPath).getInputStream();
            clientStore.load(inputStream, passArray);
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(clientStore, passArray);
            KeyManager[] kms = kmf.getKeyManagers();
            SSLContext sslContext = SSLContext.getInstance(tlsVersion);
            sslContext.init(kms, null, new SecureRandom());
            return sslContext;
        } catch (Exception ex) {
            throw new RuntimeException(String.format("SSL context load exception [SubException:%s,message:%s]", ex.getClass().getName(), ex.getMessage()), ex);
        }


    }
}
